package com.newly.center.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.newly.center.business.service.CheckRecordService;
import com.newly.center.business.service.VehicleService;
import com.newly.common.base.constants.AuthConstant;
import com.newly.common.base.constants.CodeConstant;
import com.newly.common.base.entity.auth.ICurrentTenant;
import com.newly.common.base.entity.business.Dto.CheckRecordDto;
import com.newly.common.base.entity.business.Dto.DataQueryDto;
import com.newly.common.base.entity.business.Po.CheckRecord;
import com.newly.common.base.entity.business.Po.Media;
import com.newly.common.base.entity.business.Po.Site;
import com.newly.common.base.entity.business.Po.Vehicle;
import com.newly.common.base.entity.business.Vo.*;
import com.newly.common.base.entity.business.enums.AxleNum;
import com.newly.common.base.entity.business.enums.OverweightType;
import com.newly.common.base.exception.NewlyException;
import com.newly.common.core.utils.CopyUtil;
import com.newly.common.core.utils.PageUtil;
import com.newly.common.core.utils.RequestUtils;
import com.newly.common.mapper.business.CheckRecordMapper;
import com.newly.common.mapper.business.CompanyMapper;
import com.newly.common.mapper.business.MediaMapper;
import com.newly.common.mapper.business.SiteMapper;
import com.newly.common.mapper.sys.DictMapper;
import com.newly.transfer.redis.RedisTransfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @anthor sbq
 * @date 2021/11/4 10:57
 */
@Service("checkRecordService")
public class CheckRecordServiceImpl extends ServiceImpl<CheckRecordMapper, CheckRecord> implements CheckRecordService {

    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private SiteMapper siteMapper;
    @Autowired
    private DictMapper dictMapper;
    @Autowired
    private VehicleService vehicleService;
    @Autowired
    private CheckRecordMapper checkRecordMapper;
    @Autowired
    private MediaMapper mediaMapper;
    @Autowired
    private RedisTransfer redisTransfer;

    @Autowired
    private RequestUtils requestUtils;


    @Override
    public void export(HttpServletResponse response, DataQueryDto dataQueryDto) {
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            String encode = URLEncoder.encode("检测记录表", "utf-8");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + encode + ExcelTypeEnum.XLSX.getValue());
        } catch (IOException e) {
            e.printStackTrace();
        }
        ExcelWriter write = EasyExcel.write(os, ExcelCheckRecord.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build();
        //获取总数据数量
        dataQueryDto.setPageSize(1);
        int size = this.getPage(dataQueryDto).getTotalCount();
        if (size < 1) {
            throw new NewlyException(CodeConstant.FAILED, "无检测记录数据");
        }
        //每页数量
        int page = 50000;
        for (int i = 0; i < (size / page) + 1; i++) {
            dataQueryDto.setPageNum(i + 1);
            dataQueryDto.setPageSize(page);
            List<CheckRecordVo> vos = (List<CheckRecordVo>) this.getPage(dataQueryDto).getList();

            List<ExcelCheckRecord> list = vos.stream().map(vo -> {
                ExcelCheckRecord data = BeanUtil.copyProperties(vo, ExcelCheckRecord.class);
                Integer isAudit = vo.getIsAudit();
                data.setIsAudit((isAudit != null && isAudit == 1) ? "是" : "否");
                String overweightType;
                switch (vo.getOverweightType()) {
                    case 0:
                        overweightType = "没有超重";
                        break;
                    case 1:
                        overweightType = "轻度超重";
                        break;
                    case 2:
                        overweightType = "较轻超重";
                        break;
                    case 3:
                        overweightType = "严重超重";
                        break;
                    default:
                        overweightType = "";
                }
                data.setOverweightType(overweightType);
                return data;
            }).collect(Collectors.toList());

            WriteSheet sheet = EasyExcel.writerSheet(i, "sheet" + (i + 1)).build();
            write.write(list, sheet);
        }
        write.finish();
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public PageUtil getPage(DataQueryDto dataQueryDto) {

        ICurrentTenant currentTenant = requestUtils.getCurrentTenant();
        List<String> entityIds = currentTenant.getEntityIds(AuthConstant.AuthEntityType.SITE);
        if (ObjectUtil.isEmpty(entityIds)) return new PageUtil();
        dataQueryDto.setSiteIds(entityIds);

        //从redis获取标重值
        String twoAxleWeight = this.redisTransfer.get("10016", String.class);
        String threeAxleWeight = this.redisTransfer.get("10017", String.class);
        String fourAxleWeight = this.redisTransfer.get("10018", String.class);
        String fiveAxleWeight = this.redisTransfer.get("10019", String.class);
        String sixAxleWeight = this.redisTransfer.get("10020", String.class);
        String mildCoefficient = this.redisTransfer.get("10021", String.class);
        String lighterCoefficient = this.redisTransfer.get("10022", String.class);
        dataQueryDto.setTwoAxleWeight(twoAxleWeight);
        dataQueryDto.setThreeAxleWeight(threeAxleWeight);
        dataQueryDto.setFourAxleWeight(fourAxleWeight);
        dataQueryDto.setFiveAxleWeight(fiveAxleWeight);
        dataQueryDto.setSixAxleWeight(sixAxleWeight);
        dataQueryDto.setMildCoefficient(mildCoefficient);
        dataQueryDto.setLighterCoefficient(lighterCoefficient);

        Page<CheckRecordVo> page = new Page<>(dataQueryDto.getPageNum(), dataQueryDto.getPageSize());
        page = this.checkRecordMapper.getPage(page, dataQueryDto);
        if (ObjectUtil.isEmpty(page.getRecords())) return new PageUtil(page);

        List<CheckRecordVo> checkRecordVos = page.getRecords();
        checkRecordVos = this.cover(checkRecordVos);
        checkRecordVos = checkRecordVos.stream().peek(p -> p.setTimestamp(new DateTime(p.getCreateTime())
                .getTime())).collect(Collectors.toList());
        //按时间戳排序
        checkRecordVos.sort(Comparator.comparing(CheckRecordVo::getTimestamp, Comparator.reverseOrder()));
        page.setRecords(checkRecordVos);
        return new PageUtil(page);
    }

    @Override
    public DetailsVo<CheckRecordVo> getDetailsById(Integer id) {
        DetailsVo<CheckRecordVo> detailsVo = new DetailsVo<>();
        List<CheckRecord> checkRecordList = this.getListByCondition(new CheckRecordDto().setId(id).setFlag(false));
        if (ObjectUtil.isEmpty(checkRecordList))
            throw new NewlyException("请检查id是否正确");
        List<CheckRecordVo> checkRecordVos = CopyUtil.copyList(checkRecordList, CheckRecordVo.class);
        checkRecordVos = this.cover(checkRecordVos);
        List<String> carIds = checkRecordVos.stream().map(CheckRecordVo::getCarId).collect(Collectors.toList());
        List<Vehicle> vehicleList = this.vehicleService.list(new LambdaQueryWrapper<Vehicle>().in(Vehicle::getId, carIds).eq(Vehicle::getIsDeleted, 0));
        if (ObjectUtil.isEmpty(vehicleList))
            throw new NewlyException("检测记录的车辆在车辆表不存在，请联系管理员");
        detailsVo.setEntity(checkRecordVos.get(0));
        List<Media> mediaList = this.mediaMapper.selectList(new QueryWrapper<Media>().lambda().select(Media::getTypeCode, Media::getType, Media::getPictureUrl).eq(Media::getOrderId, id).eq(Media::getIsDeleted, 0));
        mediaList = mediaList.stream().filter(p -> !StringUtils.isEmpty(p.getPictureUrl())).collect(Collectors.toList());
        detailsVo.setMediaUrl(mediaList);
        return detailsVo;
    }

    @Override
    public void audit(CheckRecord checkRecord) {

        List<Site> sites = this.siteMapper.selectList(new LambdaQueryWrapper<Site>().eq(Site::getName, checkRecord.getSiteName()).eq(Site::getIsDeleted, 0));
        if (ObjectUtil.isEmpty(sites))
            throw new NewlyException("站点名称有误，请联系管理员！");
        CheckRecord record = this.getOne(new LambdaQueryWrapper<CheckRecord>().eq(CheckRecord::getId, checkRecord.getId()));
        if (ObjectUtil.isEmpty(record))
            throw new NewlyException("请检查检测记录id是否正确");
        record.setColor(checkRecord.getColor());
        record.setSiteId(sites.get(0).getId());
        record.setTotalWeight(checkRecord.getTotalWeight());
        record.setAxleNum(checkRecord.getAxleNum());
        record.setCarType(checkRecord.getCarType());
        record.setCarNum(checkRecord.getCarNum());
        record.setIsAudit(checkRecord.getFlag() == 1 ? 2 : 1);
        record.setOpinion(checkRecord.getOpinion());
        this.updateById(record);
        Vehicle vehicle;
        //如果目标车辆已存在则更新目标车辆的信息，否则根据车辆id修改相应的记录
        if (this.vehicleService.repeat(checkRecord.getCarNum())) {
            vehicle = this.vehicleService.getOne(new LambdaQueryWrapper<Vehicle>().eq(Vehicle::getVehicleNumber, checkRecord.getCarNum()).eq(Vehicle::getIsDeleted, 0));
            vehicle.setColor(checkRecord.getColor());
            vehicle.setAxleCount(checkRecord.getAxleNum());
            vehicle.setVehicleType(checkRecord.getCarType());
            this.vehicleService.updateById(vehicle);
        } else {
            vehicle = this.vehicleService.getOne(new LambdaQueryWrapper<Vehicle>().eq(Vehicle::getId, checkRecord.getCarId()).eq(Vehicle::getIsDeleted, 0));
            if (ObjectUtil.isEmpty(vehicle))
                throw new NewlyException("请检查车辆id是否正确");
            vehicle.setColor(checkRecord.getColor());
            vehicle.setAxleCount(checkRecord.getAxleNum());
            vehicle.setVehicleType(checkRecord.getCarType());
            vehicle.setVehicleNumber(checkRecord.getCarNum());
            this.vehicleService.updateById(vehicle);
        }

    }

    @Override
    public List<OverweightRankingVo> getOverweightRanking(List<CheckRecordVo> checkRecordVos) {

        List<CheckRecordVo> checkRecordVoList = checkRecordVos;
        List<OverweightRankingVo> rankingVos;
        //按超重率倒序
        checkRecordVoList.sort(Comparator.comparing(CheckRecordVo::getOverRate, Comparator.reverseOrder()));
        //过滤误识别的数据
        checkRecordVoList = checkRecordVoList.stream().filter(p -> !p.getCarNum().startsWith("误识别")).collect(Collectors.toList());
        //取前10条记录
        checkRecordVoList = checkRecordVoList.subList(0, Math.min(checkRecordVoList.size(), 10));
        rankingVos = CopyUtil.copyList(checkRecordVoList, OverweightRankingVo.class);
        return rankingVos;
    }

    @Override
    public List<CheckRecord> getListByCondition(CheckRecordDto checkRecordDto) {

        List<CheckRecord> checkRecordList = new ArrayList<>();
        if (ObjectUtil.isEmpty(checkRecordDto))
            return checkRecordList;
        //从redis获取标重值
        String twoAxleWeight = this.redisTransfer.get("10016", String.class);
        String threeAxleWeight = this.redisTransfer.get("10017", String.class);
        String fourAxleWeight = this.redisTransfer.get("10018", String.class);
        String fiveAxleWeight = this.redisTransfer.get("10019", String.class);
        String sixAxleWeight = this.redisTransfer.get("10020", String.class);
        checkRecordList = this.list(new QueryWrapper<CheckRecord>().lambda()
                .apply("((total_weight - std_weight)/std_weight <= 1.1 or site_id <> '1460493637929418756')")
                .eq(!ObjectUtil.isEmpty(checkRecordDto.getId()), CheckRecord::getId, checkRecordDto.getId())
                .in(!ObjectUtil.isEmpty(checkRecordDto.getCarNumbers()), CheckRecord::getCarNum, checkRecordDto.getCarNumbers())
                .in(!ObjectUtil.isEmpty(checkRecordDto.getSiteIds()), CheckRecord::getSiteId, checkRecordDto.getSiteIds())
                .ge(!ObjectUtil.isEmpty(checkRecordDto.getStartTime()), CheckRecord::getCreateTime, checkRecordDto.getStartTime())
                .le(!ObjectUtil.isEmpty(checkRecordDto.getEndTime()), CheckRecord::getCreateTime, checkRecordDto.getEndTime())
                .and(checkRecordDto.getFlag(), x -> x.or(y -> y.gt(CheckRecord::getTotalWeight, twoAxleWeight).and(z -> z.eq(CheckRecord::getAxleNum, AxleNum.两轴.getCode())))
                        .or(y -> y.gt(CheckRecord::getTotalWeight, threeAxleWeight).and(z -> z.eq(CheckRecord::getAxleNum, AxleNum.三轴.getCode())))
                        .or(y -> y.gt(CheckRecord::getTotalWeight, fourAxleWeight).and(z -> z.eq(CheckRecord::getAxleNum, AxleNum.四轴.getCode())))
                        .or(y -> y.gt(CheckRecord::getTotalWeight, fiveAxleWeight).and(z -> z.eq(CheckRecord::getAxleNum, AxleNum.五轴.getCode())))
                        .or(y -> y.gt(CheckRecord::getTotalWeight, sixAxleWeight).and(z -> z.eq(CheckRecord::getAxleNum, AxleNum.六轴.getCode())))
                ));
        if (ObjectUtil.isEmpty(checkRecordList))
            return checkRecordList;
        List<Long> siteIds = checkRecordList.stream().map(CheckRecord::getSiteId).distinct().collect(Collectors.toList());
        List<Site> siteList = this.siteMapper.selectList(new QueryWrapper<Site>().lambda().in(Site::getId, siteIds).eq(Site::getIsDeleted, 0));
        //设置站点名称
        checkRecordList = checkRecordList.stream().map(p -> siteList.stream().filter(m ->
                Objects.equals(p.getSiteId(), m.getId())).findFirst()
                .map(m -> {
                    p.setSiteName(m.getName());
                    return p;
                }).orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        List<String> carNums = checkRecordList.stream().map(CheckRecord::getCarNum).distinct().collect(Collectors.toList());
        if (!ObjectUtil.isEmpty(carNums)) {
            List<Vehicle> vehicleList = this.vehicleService.list(new QueryWrapper<Vehicle>().lambda().in(Vehicle::getVehicleNumber, carNums).eq(Vehicle::getIsDeleted, 0));
            //设置车辆颜色、车辆id
            checkRecordList = checkRecordList.stream().map(p -> vehicleList.stream().filter(m ->
                    Objects.equals(p.getCarNum(), m.getVehicleNumber())).findFirst()
                    .map(m -> {
                        p.setCarId(m.getId());
                        p.setColor(m.getColor());
                        return p;
                    }).orElse(null))
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        return checkRecordList;
    }

    @Override
    public List<CheckRecordVo> cover(List<CheckRecordVo> checkRecordVos) {
        List<CheckRecordVo> checkRecordVoList = new ArrayList<>();
        //从redis获取标重值
        String twoAxleWeight = this.redisTransfer.get("10016", String.class);
        String threeAxleWeight = this.redisTransfer.get("10017", String.class);
        String fourAxleWeight = this.redisTransfer.get("10018", String.class);
        String fiveAxleWeight = this.redisTransfer.get("10019", String.class);
        String sixAxleWeight = this.redisTransfer.get("10020", String.class);
        String mildCoefficient = this.redisTransfer.get("10021", String.class);
        String lighterCoefficient = this.redisTransfer.get("10022", String.class);
        //按轴数分组
        Map<Integer, List<CheckRecordVo>> map = checkRecordVos.stream().collect(Collectors.groupingBy(CheckRecordVo::getAxleNum));
        checkRecordVos.clear();
        for (Map.Entry<Integer, List<CheckRecordVo>> entry : map.entrySet()) {
            checkRecordVos = entry.getValue();
            //根据标重参数临时修改超重量与超重率
            switch (AxleNum.getAxleType(entry.getKey())) {
                case 两轴: {
                    checkRecordVos = checkRecordVos.stream().peek(t -> {
                        t.setStdWeight(Double.valueOf(twoAxleWeight));
                        t.setOverWeight(t.getTotalWeight() <= t.getStdWeight() ? 0 : NumberUtil.round(t.getTotalWeight() - t.getStdWeight(), 0).doubleValue());
                        double overRate = t.getOverWeight() / t.getStdWeight();
                        overRate = NumberUtil.round(overRate, 4).doubleValue();
                        t.setOverRate(t.getTotalWeight() == 0 ? 0 : overRate);
                    }).collect(Collectors.toList());
                }
                break;
                case 三轴: {
                    checkRecordVos = checkRecordVos.stream().peek(t -> {
                        t.setStdWeight(Double.valueOf(threeAxleWeight));
                        t.setOverWeight(t.getTotalWeight() <= t.getStdWeight() ? 0 : NumberUtil.round(t.getTotalWeight() - t.getStdWeight(), 0).doubleValue());
                        double overRate = t.getOverWeight() / t.getStdWeight();
                        overRate = NumberUtil.round(overRate, 4).doubleValue();
                        t.setOverRate(t.getTotalWeight() == 0 ? 0 : overRate);
                    }).collect(Collectors.toList());
                }
                break;
                case 四轴: {
                    checkRecordVos = checkRecordVos.stream().peek(t -> {
                        t.setStdWeight(Double.valueOf(fourAxleWeight));
                        t.setOverWeight(t.getTotalWeight() <= t.getStdWeight() ? 0 : NumberUtil.round(t.getTotalWeight() - t.getStdWeight(), 0).doubleValue());
                        double overRate = t.getOverWeight() / t.getStdWeight();
                        overRate = NumberUtil.round(overRate, 4).doubleValue();
                        t.setOverRate(t.getTotalWeight() == 0 ? 0 : overRate);
                    }).collect(Collectors.toList());
                }
                break;
                case 五轴: {
                    checkRecordVos = checkRecordVos.stream().peek(t -> {
                        t.setStdWeight(Double.valueOf(fiveAxleWeight));
                        t.setOverWeight(t.getTotalWeight() <= t.getStdWeight() ? 0 : NumberUtil.round(t.getTotalWeight() - t.getStdWeight(), 0).doubleValue());
                        double overRate = t.getOverWeight() / t.getStdWeight();
                        overRate = NumberUtil.round(overRate, 4).doubleValue();
                        t.setOverRate(t.getTotalWeight() == 0 ? 0 : overRate);
                    }).collect(Collectors.toList());
                }
                break;
                case 六轴: {
                    checkRecordVos = checkRecordVos.stream().peek(t -> {
                        t.setStdWeight(Double.valueOf(sixAxleWeight));
                        t.setOverWeight(t.getTotalWeight() <= t.getStdWeight() ? 0 : NumberUtil.round(t.getTotalWeight() - t.getStdWeight(), 0).doubleValue());
                        double overRate = t.getOverWeight() / t.getStdWeight();
                        overRate = NumberUtil.round(overRate, 4).doubleValue();
                        t.setOverRate(t.getTotalWeight() == 0 ? 0 : overRate);
                    }).collect(Collectors.toList());
                }
                break;
            }
            checkRecordVoList.addAll(checkRecordVos);
        }
        //设置超重类型
        for (CheckRecordVo checkRecordVo : checkRecordVoList) {
            if (checkRecordVo.getOverRate() <= Double.valueOf(mildCoefficient) && checkRecordVo.getOverRate() > 0)
                checkRecordVo.setOverweightType(OverweightType.轻度超重.getCode());
            else if (checkRecordVo.getOverRate() > Double.valueOf(mildCoefficient) && checkRecordVo.getOverRate() <= Double.valueOf(lighterCoefficient))
                checkRecordVo.setOverweightType(OverweightType.较轻超重.getCode());
            else if (checkRecordVo.getOverRate() >= Double.valueOf(lighterCoefficient))
                checkRecordVo.setOverweightType(OverweightType.严重超重.getCode());
            else
                checkRecordVo.setOverweightType(OverweightType.没有超重.getCode());
        }
        checkRecordVoList = checkRecordVoList.stream().peek(p -> p.setTotalWeight(NumberUtil.round(p.getTotalWeight(), 0).doubleValue())).collect(Collectors.toList());
        return checkRecordVoList;
    }

    @Override
    public List<LastXDayTrendVo> trend(List<CheckRecordVo> checkRecordVos, Integer offset) {

        //深度克隆，生成checkRecordVos副本
        List<CheckRecordVo> checkRecordVoList = ObjectUtil.cloneByStream(checkRecordVos);
        List<LastXDayTrendVo> trendVos = new ArrayList<>();
        for (int i = 0; i < offset; i++) {
            LastXDayTrendVo trendVo = new LastXDayTrendVo();
            trendVo.setTotalNum(0);
            trendVo.setNormalNum(0);
            trendVo.setOverweightNum(0);
            trendVo.setDate(DateUtil.offsetDay(DateUtil.date(), -i).toString(DatePattern.NORM_DATE_FORMAT));
            trendVos.add(trendVo);
        }
        //修改日期为yyyy-MM-dd格式
        checkRecordVoList = checkRecordVoList.stream().peek(t -> {
            t.setCreateTime(new DateTime(t.getCreateTime()).toString(DatePattern.NORM_DATE_FORMAT));
        }).collect(Collectors.toList());
        //按日期分组
        Map<String, List<CheckRecordVo>> map = checkRecordVoList.stream().collect(Collectors.groupingBy(CheckRecordVo::getCreateTime));
        for (Map.Entry<String, List<CheckRecordVo>> entry : map.entrySet()) {
            trendVos.forEach(p -> {
                if (p.getDate().equals(entry.getKey())) {
                    p.setTotalNum(entry.getValue().size());
                    p.setNormalNum((int) entry.getValue().stream().filter(m -> m.getOverweightType() == 0).count());
                    p.setOverweightNum(p.getTotalNum() - p.getNormalNum());
                }
            });
        }
        return trendVos;
    }

    @Override
    public List<LastXDayOverweightVo> Overweight(List<CheckRecordVo> checkRecordVos, Integer offset) {

        List<CheckRecordVo> checkRecordVoList = ObjectUtil.cloneByStream(checkRecordVos);
        List<LastXDayOverweightVo> overweightVos = new ArrayList<>();
        for (int i = 0; i < offset; i++) {
            LastXDayOverweightVo overweightVo = new LastXDayOverweightVo();
            overweightVo.setOverweightNum(0);
            overweightVo.setDate(DateUtil.offsetDay(DateUtil.date(), -i).toString(DatePattern.NORM_DATE_FORMAT));
            overweightVos.add(overweightVo);
        }
        //修改日期为yyyy-MM-dd格式
        checkRecordVoList = checkRecordVoList.stream().peek(t -> {
            t.setCreateTime(new DateTime(t.getCreateTime()).toString(DatePattern.NORM_DATE_FORMAT));
        }).collect(Collectors.toList());
        //按日期分组
        Map<String, List<CheckRecordVo>> map = checkRecordVoList.stream().collect(Collectors.groupingBy(CheckRecordVo::getCreateTime));
        for (Map.Entry<String, List<CheckRecordVo>> entry : map.entrySet()) {
            overweightVos.forEach(p -> {
                if (entry.getKey().equals(p.getDate()))
                    p.setOverweightNum((int) entry.getValue().stream().filter(m -> m.getOverweightType() != 0).count());
            });
        }
        return overweightVos;
    }

    @Override
    public List<LastXDayRankingVo> Ranking(List<CheckRecordVo> checkRecordVos) {

        List<LastXDayRankingVo> rankingVos = new ArrayList<>();
        List<Site> siteList = this.siteMapper.selectList(new LambdaQueryWrapper<Site>().eq(Site::getIsDeleted, 0));
        for (Site site : siteList) {
            LastXDayRankingVo rankingVo = new LastXDayRankingVo();
            rankingVo.setSiteId(site.getId().toString());
            rankingVo.setSiteName(site.getName());
            rankingVo.setTotalNum(0);
            rankingVo.setOverweightNum(0);
            rankingVo.setOverweightPercent(0.0);
            rankingVos.add(rankingVo);
        }
        //按站点名称分组
        Map<String, List<CheckRecordVo>> map = checkRecordVos.stream().collect(Collectors.groupingBy(CheckRecordVo::getSiteName));
        for (Map.Entry<String, List<CheckRecordVo>> entry : map.entrySet()) {
            rankingVos.forEach(p -> {
                if (p.getSiteName().equals(entry.getKey())) {
                    p.setTotalNum(entry.getValue().size());
                    p.setOverweightNum((int) entry.getValue().stream().filter(t -> t.getOverweightType() != 0).count());
                    p.setOverweightPercent(NumberUtil.round((double) p.getOverweightNum() / p.getTotalNum(), 4).doubleValue());
                }
            });

        }
        //按超重百分比倒序取前面十条数据
        rankingVos.sort(Comparator.comparing(LastXDayRankingVo::getOverweightPercent, Comparator.reverseOrder()));
        return rankingVos.subList(0, rankingVos.size() >= 10 ? 10 : rankingVos.size());
    }

    @Override
    public List<AxleCountVo> axleCount(List<CheckRecordVo> checkRecordVos) {

        List<AxleCountVo> axleCountVos = new ArrayList<>();
        double rate;
        //按轴数分组
        Map<Integer, List<CheckRecordVo>> map = checkRecordVos.stream().collect(Collectors.groupingBy(CheckRecordVo::getAxleNum));
        for (Map.Entry<Integer, List<CheckRecordVo>> entry : map.entrySet()) {
            AxleCountVo axleCountVo = new AxleCountVo();
            axleCountVo.setAxleNum(entry.getKey());
            rate = entry.getValue().stream().mapToDouble(CheckRecordVo::getOverRate).average().orElse(0.00);
            axleCountVo.setAvgOverweightRate(NumberUtil.round(rate, 4).doubleValue());
            axleCountVo.setOverweightNum((int) entry.getValue().stream().filter(t -> t.getOverweightType() != 0).count());
            axleCountVos.add(axleCountVo);
        }
        return axleCountVos;
    }

    @Override
    public List<RealTimeVo> getRealTimeData(Integer limit) {
        List<RealTimeVo> realTimeVos = new ArrayList<>();
        List<CheckRecord> checkRecordList = this.list(new QueryWrapper<CheckRecord>().lambda()
                .notLike(CheckRecord::getCarNum, "误识别")
                .orderByDesc(CheckRecord::getId).last("limit " + limit));
        if (ObjectUtil.isEmpty(checkRecordList)) return realTimeVos;

        List<Long> siteIds = checkRecordList.stream().map(CheckRecord::getSiteId).collect(Collectors.toList());
        List<Site> siteList = this.siteMapper.selectList(new LambdaQueryWrapper<Site>().in(Site::getId, siteIds));
        //设置站点名称
        checkRecordList = checkRecordList.stream().map(p -> siteList.stream().filter(m ->
                Objects.equals(p.getSiteId(), m.getId())).findFirst()
                .map(m -> {
                    p.setSiteName(m.getName());
                    return p;
                }).orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        List<CheckRecordVo> checkRecordVos = CopyUtil.copyList(checkRecordList, CheckRecordVo.class);
        checkRecordVos = this.cover(checkRecordVos);
        realTimeVos = CopyUtil.copyList(checkRecordVos, RealTimeVo.class);
        return realTimeVos;
    }
}
